package com.bootx.predict;

import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.predict.pojo.PredictionResult;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.RedPacketRecord;
import com.bootx.predict.util.PredictUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component("weightedDecayPenaltyPredict")
public class WeightedDecayPenaltyPredict extends PredictPlugin {

    /**
     * 如果红包批次很多（>50 轮），lambda ≈ 0.02
     * 如果批次不多（10-20 轮），lambda ≈ 0.05
     */
    private final double lambda = 0.03;
    /**
     * 作用：防止某个 index 连续出现奇数后仍高概率预测奇数。
     * 推荐范围：0.02 ~ 0.05
     */
    private final double penaltyFactor = 0.03;

    @Override
    public String getName() {
        return "weightedDecayPenaltyPredict";
    }

    @Override
    public List<PredictionResult> predict(List<RedPacketBatch> list, Set<Integer> indexes) {
        List<RedPacketRecord> history = PredictUtils.parseData(list);
        // 按 index 分组
        Map<Integer, List<RedPacketRecord>> grouped = history.stream()
                .collect(Collectors.groupingBy(RedPacketRecord::getIndex));

        List<PredictionResult> results = new ArrayList<>();
        for (int idx : indexes) {
            List<RedPacketRecord> records = grouped.getOrDefault(idx, Collections.emptyList());
            if (records.isEmpty()) {
                results.add(new PredictionResult(idx, 0, 0, 0.5, 0));
                continue;
            }

            // 按时间顺序排序
            records.sort(Comparator.comparingLong(RedPacketRecord::getRoundId));
            int total = records.size();
            int oddCount = 0;
            double weightedSum = 0;
            double weightTotal = 0;

            // 计算权重和概率
            for (int i = 0; i < records.size(); i++) {
                boolean odd = PredictUtils.isAmountOdd(records.get(i).getAmount());
                if (odd) {
                    oddCount++;
                }
                double weight = Math.exp(-lambda * (records.size() - 1 - i));
                weightedSum += (odd ? 1 : 0) * weight;
                weightTotal += weight;
            }

            double baseProb = weightedSum / weightTotal;

            // 计算连续奇数 streak
            int streakOdd = 0;
            for (int i = records.size() - 1; i >= 0; i--) {
                if (PredictUtils.isAmountOdd(records.get(i).getAmount())) {
                    streakOdd++;
                } else {
                    break;
                }
            }

            // 惩罚
            double penalty = streakOdd * penaltyFactor;
            double finalProb = baseProb - penalty;
            if (finalProb < 0.01) {
                finalProb = 0.01;
            }
            if (finalProb > 0.99) {
                finalProb = 0.99;
            }
            double avgOpenTime = records.stream().mapToInt(RedPacketRecord::getOpenTime).average().orElse(0);

            results.add(new PredictionResult(idx, total, oddCount, finalProb, Double.valueOf(avgOpenTime+"").intValue()));
        }

        return results;
    }
}
